import { app, shell, BrowserWindow, ipcMain, dialog } from 'electron'
import type { FileFilter } from 'electron'
import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import path from 'path'
import puppeteer from 'puppeteer-core'
import os from 'os'
import fs from 'fs/promises'

import type { Page } from 'puppeteer-core'

import icon from '../../resources/icon.png?asset'
// import dy_getLiveScript from './scripts/dy_getLive.js?asset'
import dy_sj from './scripts/dy_sj.js?asset'
import { writeFile } from './util'

let openedCache = {}

interface IConfig {
  id?: string
  name?: string
  memo?: string
  urls?: string
  tag?: string
  headless?: boolean
  [key: string]: unknown
}

function createWindow(): void {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 900,
    height: 670,
    show: false,
    autoHideMenuBar: true,
    ...(process.platform === 'linux' ? { icon } : {}),
    webPreferences: {
      preload: join(__dirname, '../preload/index.js'),
      sandbox: false
      // devTools: is.dev
    }
  })
  // if (is.dev) {
  //   mainWindow.webContents.openDevTools()
  // }

  mainWindow.on('ready-to-show', () => {
    mainWindow.show()
  })

  mainWindow.on('close', (e) => {
    const keys = Object.keys(openedCache)
    if (!keys.length) return
    e.preventDefault()
    dialog
      .showMessageBox({
        type: 'warning',
        title: '警告',
        message: '还有未关闭的浏览器窗口，是否确认退出？',
        buttons: ['取消', '确认退出'],
        cancelId: 0
      })
      .then(async ({ response }) => {
        if (response === 1) {
          for (const key of keys) {
            await closeChrome(key)
          }
          mainWindow.close()
          app.quit()
        }
      })
  })

  mainWindow.webContents.setWindowOpenHandler((details) => {
    shell.openExternal(details.url)
    return { action: 'deny' }
  })

  const filters: FileFilter[] = []

  if (process.platform === 'darwin') {
    filters.push({
      name: 'app',
      extensions: ['app']
    })
  } else {
    filters.push({
      name: 'exe',
      extensions: ['exe']
    })
  }

  ipcMain.on('selectChromePath', async () => {
    try {
      const res = await dialog.showOpenDialog({
        title: '选择谷歌浏览器地址',
        properties: ['openFile'],
        message: '选择谷歌浏览器地址',
        filters
      })
      const chromePath = res.filePaths[0]
      if (chromePath) {
        mainWindow.webContents.send('selectChromePath', chromePath)
      }
    } catch (error) {
      console.log(error)
    }
  })
  ipcMain.on('openChrome', async (_, params) => {
    const { _chromePath, ...rest } = params
    let chromePath = _chromePath
    //  // 处理Mac，获取真实二进制文件
    if (process.platform === 'darwin') {
      chromePath = `${chromePath}/Contents/MacOS/Google Chrome`
    } else {
      chromePath = chromePath.replace(/\\/g, '\\\\')
    }
    const instance = await openChrome(chromePath, rest)
    if (openedCache[params.id]) {
      await openedCache[params.id].instance.close()
    }
    openedCache[params.id!] = {
      isOpen: true,
      instance
    }
    mainWindow.webContents.send('openChromeSuccess', params.id)
  })
  async function closeChrome(id: string) {
    const { instance, isOpen } = openedCache[id] || {}
    if (isOpen) {
      await instance.close()
      delete openedCache[id]
    }
  }
  ipcMain.on('closeChrome', async (_, id) => {
    await closeChrome(id)
    mainWindow.webContents.send('closeChrome', id)
  })

  ipcMain.on('openExternalLink', (_, url) => {
    shell.openExternal(url)
  })

  ipcMain.on('exportConfig', async (_, config) => {
    console.log(config)
    const { filePath } = await dialog.showSaveDialog(mainWindow, {
      title: '选择导出位置',
      defaultPath: path.join(os.homedir(), 'Desktop', '谷歌多开助手配置.json'),
      buttonLabel: '保存'
    })
    if (!filePath) {
      return
    }
    console.log(filePath)
    await writeFile(filePath, JSON.stringify(config, null, 2))
  })

  // HMR for renderer base on electron-vite cli.
  // Load the remote URL for development or the local html file for production.
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
  } else {
    mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
  }
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
  // Set app user model id for windows
  electronApp.setAppUserModelId('top.sayto.chrome.multiple')

  // Default open or close DevTools by F12 in development
  // and ignore CommandOrControl + R in production.
  // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
  app.on('browser-window-created', (_, window) => {
    optimizer.watchWindowShortcuts(window)
  })

  // IPC test
  // ipcMain.on('ping', () => console.log('pong'))

  createWindow()

  app.on('activate', function () {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

// In this file you can include the rest of your app"s specific main process
// code. You can also put them in separate files and require them here.

async function openChrome(appPath: string, args: IConfig) {
  try {
    const { id, urls, headless } = args
    const browser = await puppeteer.launch({
      devtools: false,
      headless: !!headless,
      executablePath: appPath,
      defaultViewport: {
        width: 0,
        height: 0
      },
      userDataDir: path.join(os.homedir(), '.puppeteer-user-data', id!),
      args: ['--no-sandbox']
    })
    const openUrls = urls?.split('\n') || []
    for (const url of openUrls) {
      const page = await browser.newPage()
      await page.goto(url)
      if (args.tag === 'dy_sj' && url.match(/douyin\.com/)) {
        handleDySjScript(page, args)
      }
    }
    return browser
    // await chrome.newPage()
  } catch (error) {
    console.log(error)
    throw error
  }
}

async function handleDySjScript(page: Page, args: IConfig) {
  let timer: NodeJS.Timeout
  timer = setInterval(async () => {
    const dom = await page.$('div[data-e2e=user-detail] .semi-avatar-wrapper')
    if (dom) {
      const href = await page.$eval(
        'div[data-e2e=user-detail] a:has(.semi-avatar-wrapper)',
        (e) => {
          return e.getAttribute('href')
        }
      )
      if (href) {
        clearInterval(timer)
        await page.goto(href)
        const content = await fs.readFile(dy_sj, 'utf-8')
        page.evaluate((config) => {
          // @ts-ignore
          window.DYCONFIG = config
        }, args)

        page.addScriptTag({
          content
        })
      }
    }
  }, 1000)
}
